package com.dci.intellij.dbn2.utils;

import com.intellij.openapi.actionSystem.DefaultActionGroup;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public final class ReflectionUtils {
    public static Object getFieldValue(Object object, String name) {
        try {
            Field field = getField(object.getClass(), name);
            if (field == null) {
                return null;
            }

            field.setAccessible(true);
            return field.get(object);
        } catch (Exception ex) {
        }
        return null;
    }

    public static void setFieldValue(Object object, String name, Object value) {
        try {
            Field field = getField(object.getClass(), name);
            if (field == null) {
                return;
            }

            field.setAccessible(true);
            field.set(object, value);
        } catch (Exception ex) {
        }
    }

    private static Field getField(Class<?> clazz, String name) {
        Field field = null;
        if (clazz != null) {
            try {
                field = clazz.getDeclaredField(name);
            } catch (Exception ex) {

            }
            if (field == null) {
                try {
                    field = clazz.getField(name);
                } catch (Exception ex) {

                }
            }
            if (field != null) {
                return field;
            }
            return getField(clazz.getSuperclass(), name);
        } else {
            return null;
        }
    }

    public static Object invokeMethod(Object object, String methodName, Object... args) {
        Class<?>[] argClass = null;
        if (args != null) {
            argClass = new Class<?>[args.length];
            for (int i = 0; i < args.length; i++) {
                argClass[i] = args[i].getClass();
            }
        }


        try {
            Method method = null;
            try {
                method = object.getClass().getDeclaredMethod(methodName, argClass);
            } catch (Exception ex) {

            }
            if (method == null) {
                try {
                    method = object.getClass().getMethod(methodName, argClass);
                } catch (Exception ex) {

                }
            }
            if (method == null) {
                return null;
            }

            method.setAccessible(true);
            return method.invoke(object, args);
        } catch (Exception ex) {
        }
        return null;
    }

    public static boolean instanceOf(Object object, Class clazz) {
        try {
            return object.getClass().getClassLoader().loadClass(clazz.getName()).isAssignableFrom(object.getClass());
        } catch (Exception ex) {
            return false;
        }
    }

    public static Class getSpyClass(ClassLoader classLoader, Class clazz) {
        try {
            return classLoader.loadClass(clazz.getName());
        } catch (Exception ex) {
            return null;
        }
    }

    public static Object newInstance(Class<?> clazz, Class<?>[] argClass, Object... args) {
        Constructor constructor = null;
        try {
            constructor = clazz.getDeclaredConstructor(argClass);
        } catch (Exception ex) {}
        if (constructor == null) {
            try {
                constructor = clazz.getConstructor(argClass);
            } catch (Exception ex) {}
        }
        if (constructor == null) {
            return null;
        }

        try {
            constructor.setAccessible(true);
            return constructor.newInstance(args);
        } catch (Exception ex) {
            return null;
        }
    }
}
